const fs = require('fs-extra');
const path = require('path');
const simpleGit = require('simple-git');
const axios = require('axios');
const chalk = require('chalk');
const ora = require('ora');

/**
 * 代码包下载器类
 */
class CodeDownloader {
  constructor() {
    this.git = simpleGit();
  }

  /**
   * 克隆仓库到指定目录
   * @param {string} repoUrl - 仓库URL
   * @param {string} targetDir - 目标目录
   * @param {object} options - 选项
   * @returns {Promise<string>} 克隆的目录路径
   */
  async cloneRepository(repoUrl, targetDir, options = {}) {
    const spinner = ora('正在克隆仓库...').start();
    
    try {
      // 确保目标目录的父目录存在
      await fs.ensureDir(path.dirname(targetDir));
      
      // 如果目标目录已存在，删除它
      if (await fs.pathExists(targetDir)) {
        await fs.remove(targetDir);
      }

      const cloneOptions = {
        '--depth': options.shallow ? 1 : undefined,
        '--branch': options.branch || 'master',
        '--single-branch': options.shallow ? true : undefined
      };

      // 过滤掉undefined的选项
      const filteredOptions = Object.keys(cloneOptions)
        .filter(key => cloneOptions[key] !== undefined)
        .reduce((obj, key) => {
          obj[key] = cloneOptions[key];
          return obj;
        }, {});

      await this.git.clone(repoUrl, targetDir, filteredOptions);
      
      spinner.succeed(chalk.green('仓库克隆成功'));
      return targetDir;
    } catch (error) {
      spinner.fail(chalk.red('仓库克隆失败'));
      throw new Error(`克隆仓库失败: ${error.message}`);
    }
  }

  /**
   * 下载仓库的ZIP包
   * @param {string} owner - 仓库所有者
   * @param {string} repo - 仓库名
   * @param {string} targetDir - 目标目录
   * @param {object} options - 选项
   * @returns {Promise<string>} 解压后的目录路径
   */
  async downloadZip(owner, repo, targetDir, options = {}) {
    const spinner = ora('正在下载代码包...').start();
    
    try {
      const branch = options.branch || 'master';
      const zipUrl = `https://gitee.com/${owner}/${repo}/repository/archive/${branch}.zip`;
      
      // 确保目标目录存在
      await fs.ensureDir(targetDir);
      
      // 下载ZIP文件
      const response = await axios({
        method: 'GET',
        url: zipUrl,
        responseType: 'stream'
      });

      const zipPath = path.join(targetDir, `${repo}-${branch}.zip`);
      const writer = fs.createWriteStream(zipPath);
      
      response.data.pipe(writer);

      await new Promise((resolve, reject) => {
        writer.on('finish', resolve);
        writer.on('error', reject);
      });

      spinner.succeed(chalk.green('代码包下载成功'));
      
      // 解压ZIP文件
      spinner.start('正在解压代码包...');
      const extractPath = await this.extractZip(zipPath, targetDir);
      
      // 删除ZIP文件
      await fs.remove(zipPath);
      
      spinner.succeed(chalk.green('代码包解压成功'));
      return extractPath;
    } catch (error) {
      spinner.fail(chalk.red('代码包下载失败'));
      throw new Error(`下载代码包失败: ${error.message}`);
    }
  }

  /**
   * 解压ZIP文件
   * @param {string} zipPath - ZIP文件路径
   * @param {string} extractDir - 解压目录
   * @returns {Promise<string>} 解压后的目录路径
   */
  async extractZip(zipPath, extractDir) {
    return new Promise((resolve, reject) => {
      const AdmZip = require('adm-zip');
      
      try {
        const zip = new AdmZip(zipPath);
        const entries = zip.getEntries();
        
        if (entries.length === 0) {
          reject(new Error('ZIP文件为空'));
          return;
        }

        // 获取根目录名
        const rootEntry = entries[0];
        const rootDirName = rootEntry.entryName.split('/')[0];
        
        // 解压到临时目录
        const tempDir = path.join(extractDir, 'temp');
        zip.extractAllTo(tempDir, true);
        
        // 将解压的内容移动到目标目录
        const sourceDir = path.join(tempDir, rootDirName);
        const targetPath = path.join(extractDir, rootDirName);
        
        if (fs.existsSync(sourceDir)) {
          fs.moveSync(sourceDir, targetPath);
          fs.removeSync(tempDir);
          resolve(targetPath);
        } else {
          reject(new Error('解压失败：找不到根目录'));
        }
      } catch (error) {
        reject(error);
      }
    });
  }

  /**
   * 获取仓库的克隆URL
   * @param {string} owner - 仓库所有者
   * @param {string} repo - 仓库名
   * @param {boolean} useHttps - 是否使用HTTPS
   * @returns {string} 克隆URL
   */
  getCloneUrl(owner, repo, useHttps = true) {
    if (useHttps) {
      return `https://gitee.com/${owner}/${repo}.git`;
    } else {
      return `git@gitee.com:${owner}/${repo}.git`;
    }
  }

  /**
   * 检查目录是否为空
   * @param {string} dirPath - 目录路径
   * @returns {Promise<boolean>} 是否为空
   */
  async isEmptyDirectory(dirPath) {
    try {
      const files = await fs.readdir(dirPath);
      return files.length === 0;
    } catch (error) {
      return true;
    }
  }

  /**
   * 清理目录
   * @param {string} dirPath - 目录路径
   * @returns {Promise<void>}
   */
  async cleanDirectory(dirPath) {
    try {
      if (await fs.pathExists(dirPath)) {
        await fs.remove(dirPath);
      }
    } catch (error) {
      throw new Error(`清理目录失败: ${error.message}`);
    }
  }

  /**
   * 复制目录
   * @param {string} source - 源目录
   * @param {string} target - 目标目录
   * @returns {Promise<void>}
   */
  async copyDirectory(source, target) {
    try {
      await fs.copy(source, target);
    } catch (error) {
      throw new Error(`复制目录失败: ${error.message}`);
    }
  }
}

module.exports = CodeDownloader;
